
#include <CGAL/draw_triangulation_2.h>

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
#include <CGAL/Delaunay_mesher_2.h>
#include <CGAL/Delaunay_mesh_face_base_2.h>
#include <CGAL/Delaunay_mesh_size_criteria_2.h>

#include <iostream>

typedef int Index; 

typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Triangulation_vertex_base_with_info_2<Index, K> Vb;
//typedef CGAL::Triangulation_vertex_base_2<K> Vb;
typedef CGAL::Delaunay_mesh_face_base_2<K> Fb;
typedef CGAL::Triangulation_data_structure_2<Vb, Fb> Tds;
typedef CGAL::Constrained_Delaunay_triangulation_2<K, Tds> CDT;
typedef CGAL::Delaunay_mesh_size_criteria_2<CDT> Criteria;

typedef CDT::Vertex_handle Vertex_handle;
typedef CDT::Point Point;
//typedef CGAL::Triangulation_2<K>      Triangulation;

//typedef CDT::Vertex_handle  Vertex_handle;
//typedef CDT::Finite_vertex_handles    Finite_vertex_handles;

// The following types are different
// Its value type is Triangulation_2::Vertex
//typedef CDT::Finite_vertices_iterator Finite_vertices_iterator;
// Its value type is Triangulation_2::Vertex_handle
//typedef Finite_vertex_handles::iterator         Finite_vertex_handles_iterator;



int main()
{
  CDT cdt;
  Vertex_handle va = cdt.insert(Point(2,0));
  Vertex_handle vb = cdt.insert(Point(0,2));
  Vertex_handle vc = cdt.insert(Point(-2,0));
  Vertex_handle vd = cdt.insert(Point(0,-2));

  cdt.insert_constraint(va, vb);
  cdt.insert_constraint(vb, vc);
  cdt.insert_constraint(vc, vd);
  cdt.insert_constraint(vd, va);

  va = cdt.insert(Point(3,3));
  vb = cdt.insert(Point(-3,3));
  vc = cdt.insert(Point(-3,-3));
  vd = cdt.insert(Point(3,0-3));

  cdt.insert_constraint(va, vb);
  cdt.insert_constraint(vb, vc);
  cdt.insert_constraint(vc, vd);
  cdt.insert_constraint(vd, va);

  std::list<Point> list_of_seeds;

  list_of_seeds.push_back(Point(0, 0));

  std::cout << "Number of vertices: " << cdt.number_of_vertices() << std::endl;
  std::cout << "Number of finite faces: " << cdt.number_of_faces() << std::endl;

  std::cout << "Meshing the domain..." << std::endl;
  CGAL::refine_Delaunay_mesh_2(cdt, list_of_seeds.begin(), list_of_seeds.end(),
                               Criteria(0.125, 2));

  std::cout << "Number of vertices: " << cdt.number_of_vertices() << std::endl;
  std::cout << "Number of finite faces: " << cdt.number_of_faces() << std::endl;
  int mesh_faces_counter = 0;
  for(CDT::Finite_faces_iterator fit = cdt.finite_faces_begin();
      fit != cdt.finite_faces_end(); ++fit) 
  {
    if(fit->is_in_domain()) 
    {
      ++mesh_faces_counter;
    }
  }
  std::cout << "Number of faces in the mesh domain: " << mesh_faces_counter << std::endl;


std::map<CDT::Vertex_handle, int> V;
int inum = 0;
for(CDT::Finite_vertices_iterator vit = cdt.finite_vertices_begin();
vit != cdt.finite_vertices_end();
++vit)
{
  std::cout << vit->point() << std::endl;
  vit->info() = inum;
  V[vit] = inum;
  inum++;
}



for( CDT::Finite_faces_iterator fit = cdt.finite_faces_begin();
fit != cdt.finite_faces_end(); ++fit)
{
    for (int i=0; i<3; i++)
  {
   	    Point p = fit->vertex(i)->point();
        std::cout<<"("<<p.x()<<","<<p.y()<<")"<<std::endl;
        std::cout<<fit->vertex(i)->info()<<std::endl;
 }
}




CDT::Finite_edges_iterator e_iter;
int edge_number = 0;
for (e_iter=cdt.finite_edges_begin(); e_iter!=cdt.finite_edges_end(); e_iter++)
{
  edge_number++;
  for(int i=0; i<2; i++)
  {
    Vertex_handle f_v1 = e_iter->first->vertex(cdt.cw(e_iter->second));
    Vertex_handle f_v2 = e_iter->first->vertex(cdt.ccw(e_iter->second));

    Point p1 = f_v1->point();
    Point p2 = f_v2->point();
    std::cout<<"("<<p1.x()<<","<<p1.y()<<")"<<std::endl;
    std::cout<<"edge vertex index: "<<f_v1->info()<<" "<<f_v2->info()<<std::endl;
  }

} 

std::cout<<"edge number: "<<edge_number<<std::endl;



//find edge method 1:
edge_number = 0;
for (CDT::Finite_edges_iterator eit = cdt.finite_edges_begin(); eit != cdt.finite_edges_end(); ++eit) 
{

    const CDT::Face_handle& fh = eit->first;

    int ctr = 0;
    if(fh->is_in_domain())
    {
        ctr++;
    }
    if(fh->neighbor(eit->second)->is_in_domain())
    {
        ctr++;
    }

    if(ctr == 1)
    {
        CDT::Segment s = cdt.segment(eit);
        // yeah, I get my border !!
        edge_number++;
    }
}
std::cout<<"edge number: "<<edge_number<<std::endl;



//find edge method 2: only outer boundary edge
edge_number = 0;
for (CDT::Finite_edges_iterator eit = cdt.finite_edges_begin(); eit != cdt.finite_edges_end(); ++eit) 
{
    const CDT::Face_handle& fh = eit->first;

    if (cdt.is_infinite(fh) || cdt.is_infinite(fh->neighbor(eit->second)))
    {
        // Border edge
        edge_number++;

        //eit->first->vertex(CGAL::cw(eit->second))->point();
        //eit->first->vertex(CGAL::ccw(eit->second))->point();
    }
}
std::cout<<"edge number: "<<edge_number<<std::endl;




  CGAL::draw(cdt);

}




